package codeGeneration.bean;

import java.util.ArrayList;
import java.util.List;

import lexer.TokenConstant;

import util.Common;
import util.FileUtil;
import util.Relationship;

import databaseTransaction.Table;
import databaseTransaction.TableField;

public class HibernateClassGenerator extends ClassGenerator {
	public HibernateClassGenerator(Table table, String basePath,
			String packageName, String basePackageName) {
		super(table, table.getName());
		this.packageName = packageName;
		this.fileLocation = basePath + '/' + packageName.replace('.', '/');

		FileUtil.mkDir(fileLocation);
	}

	public void generateDeclare() {
		headerOfJavaFile.setPackageName(packageName);
		generateImport();

		// add entity annotation
		appendToFile(sbuffWriter, "@Entity\n");
		appendToFile(sbuffWriter, "@Table(name = \"" + table.getName()
				+ "\")\n");

		// add class declare
		indentOneTime("public class " + this.table.getName(), null, "{",
				sbuffWriter, false);

		List<TableField> allOfField = new ArrayList<TableField>(table.getId());
		allOfField.addAll(table.getTableFields());

		// add some properties in class
		for (TableField tblField : allOfField) {
			// add annotation which mapping between property in class
			// and column in database
			String tableName;
			String lowerCaseTableName;
			if (tblField.getRelationship() != null) {
				List<Object> extra = tblField.getExtra();
				if (extra != null && extra.size() != 0
						&& extra.contains(TokenConstant.PK)) {
					if (tblField.getName().toLowerCase().endsWith("id"))
						appendToFile(sbuffWriter, "@Id\n");
					if (extra.contains("Auto-increase")) {
						appendToFile(sbuffWriter, "@GeneratedValue\n");
						generateParticularImport("javax.persistence.GeneratedValue");
					}

					appendToFile(sbuffWriter,
							"@Column(name = \"" + tblField.getName() + "\")\n");

					// add property
					appendToFile(sbuffWriter, "private " + tblField.parseType()
							+ " " + tblField.getName() + ";\n");
				}

				Relationship relationship = tblField.getRelationship();
				switch (relationship.getRelationship()) {
				case TokenConstant.MANYTOONE:
					generateParticularImport("javax.persistence.ManyToOne");
					appendToFile(sbuffWriter, "@ManyToOne\n");

					generateParticularImport("javax.persistence.JoinColumn");
					appendToFile(sbuffWriter, "@JoinColumn(name = \""
							+ relationship.getTableFieldName() + "\")\n");

					tableName = relationship.getTableName();
					appendToFile(sbuffWriter, "private " + tableName + " "
							+ Common.convertFirstLetterToLowerCase(tableName)
							+ ";\n");
					break;
				case TokenConstant.ONETOMANY:
					tableName = relationship.getTableName();
					lowerCaseTableName = Common
							.convertFirstLetterToLowerCase(tableName);
					generateParticularImport("javax.persistence.OneToMany");
					appendToFile(sbuffWriter, "@OneToMany(mappedBy = \""
							+ Common.convertFirstLetterToLowerCase(className)
							+ "\")\n");

					generateParticularImport("java.util.Set");

					appendToFile(sbuffWriter, "private Set<" + tableName + "> "
							+ lowerCaseTableName + "s;\n");
					break;
				case TokenConstant.MANYTOMANY:
					if (relationship.getOtherTableFieldName() != null
							&& !"".equals(relationship.getOtherTableFieldName())) {
						generateParticularImport("javax.persistence.ManyToMany");
						generateParticularImport("javax.persistence.CascadeType");
						generateParticularImport("javax.persistence.JoinColumn");
						generateParticularImport("java.util.Set");
						appendToFile(sbuffWriter,
								"@ManyToMany(cascade = {CascadeType.ALL})\n");

						generateParticularImport("javax.persistence.JoinTable");
						appendToFile(sbuffWriter, "@JoinTable(name = \""
								+ relationship.getTableName() + "\", \n");
						appendToFile(
								sbuffWriter,
								"joinColumns = {@JoinColumn(name = \""
										+ relationship.getTableFieldName()
										+ "\")}, "
										+ "inverseJoinColumns = {@JoinColumn(name = \""
										+ relationship.getOtherTableFieldName()
										+ "\")})\n");

						tableName = relationship.getOtherTableName();
						appendToFile(
								sbuffWriter,
								"private Set<"
										+ tableName
										+ "> "
										+ Common.convertFirstLetterToLowerCase(tableName)
										+ "s;\n");
					} else {
						generateParticularImport("javax.persistence.ManyToMany");
						generateParticularImport("java.util.Set");
						appendToFile(
								sbuffWriter,
								"@ManyToMany(mappedBy = \""
										+ Common.convertFirstLetterToLowerCase(table
												.getName()) + "s\")\n");

						tableName = relationship.getOtherTableName();
						appendToFile(
								sbuffWriter,
								"private Set<"
										+ tableName
										+ "> "
										+ Common.convertFirstLetterToLowerCase(tableName)
										+ "s;\n");
					}
					break;
				case TokenConstant.ONETOONE:
					break;
				}

			} else {
				List<Object> extra = tblField.getExtra();
				if (extra != null && extra.size() != 0) {
					if (extra.contains(TokenConstant.PK)
							&& tblField.getName().toLowerCase().endsWith("id"))
						appendToFile(sbuffWriter, "@Id\n");
					if (extra.contains("Auto-increase")) {
						generateParticularImport("javax.persistence.GeneratedValue");
						appendToFile(sbuffWriter, "@GeneratedValue\n");
					}
				}

				appendToFile(sbuffWriter,
						"@Column(name = \"" + tblField.getName() + "\")\n");

				// add property
				appendToFile(sbuffWriter, "private " + tblField.parseType()
						+ " " + tblField.getName() + ";\n");
			}
		}
	}

	private void generateImport() {
		headerOfJavaFile.addImportsList("javax.persistence.Column");
		headerOfJavaFile.addImportsList("javax.persistence.Entity");
		headerOfJavaFile.addImportsList("javax.persistence.Id");
		headerOfJavaFile.addImportsList("javax.persistence.Table");
	}

	private void generateParticularImport(String importString) {
		headerOfJavaFile.addImportsList(importString);
	}
}
